<?php
/**
 * 缓存类
 * 
 * Copyright (c) 2014~2019 https://desion.net All rights reserved.
 * Author: 阿林 QQ:120867629 <linhong00@gmail.com>
 */
declare (strict_types = 1);
namespace dsphp;

class Cache
{
    // 当前应用对象
    protected $app = null;
    // 缓存实例
    protected $instance = [];
    // 当前
    protected $name = '';
    // 配置参数
    protected $config = [];
    // 重新链接
    protected $force = false;

    /**
     * 构造方法
     */
    public function __construct(App $app, array $config)
    {
        $this->app    = $app;
        $this->config = $config;

        return $this;
    }

    /**
     * 链接缓存
     *
     * @param string $name
     * @return void
     */
    public function init(string $name)
    {
        return $this->connect($name, true);
    }

    /**
     * 连接缓存
     *
     * @param  string $name    连接配置名
     * @param  bool   $cache   
     * @return mixed
     */
    protected function connect(string $name, bool $cache = true)
    {
        if (empty($name)) {
            throw new \Exception('Cache name is empty');
        }
        // 设置当前名称
        $this->name = $name;

        if ($this->force || ! isset($this->instance[$name])) {
            if (! isset($this->config[$name])) {
                throw new \Exception('Undefined cache config:' . $name);
            }

            $namespace = 'dsphp\\cache\\'.ucfirst($name);
            $handler   = $this->app->make($namespace, [$this->config[$name]]);
    
            $this->instance[$name] = $handler;
        }

        return $cache ? $this : $this->instance[$name];
    }

    /**
     * 设置配置
     *
     * @param  array $config 配置参数
     * @param  string $name  配置名称
     * @return this
     */
    public function config(array $config, string $name = '')
    {
        if (empty($name)) {
            $this->config = array_merge($this->config, $config);
            return $this;
        }

        if (isset($this->config[$name])) {
            $this->config[$name] = array_merge($this->config[$name], $config);
        } else {
            $this->config[$name] = $config;
        }

        return $this;
    }

    /**
     * 重新链接
     *
     * @param boolean $type true 为重新链接
     * @return this
     */
    public function force(bool $type = true) 
    {
        $this->force = $type;
        return $this;
    }

    /**
     * 清空缓冲池
     */
    public function clear(): bool
    {
        return $this->_getHandler()->clear();
    }

    /**
     * 读取缓存
     *
     * @param  string $name 缓存变量名
     * @param  mixed  $default 默认值
     * @return mixed
     */
    public function get($key, $default = false)
    {
        return $this->_getHandler()->get($key, $default);
    }

    /**
     * 写入缓存
     *
     * @param  string  $name 缓存变量名
     * @param  mixed   $value  存储数据
     * @param  int     $expire  有效时间 0为永久
     */
    public function set(string $key, $value, $ttl = null): bool
    {
        return $this->_getHandler()->set($key, $value, $ttl);
    }

    /**
     * 删除缓存
     *
     * @param  string $name 缓存变量名
     */
    public function delete($key): bool
    {
        return $this->_getHandler()->delete($key);
    }

    /**
     * 追加（数组）缓存
     *
     * @param string $key   缓存变量名
     * @param mixed  $value 存储数据
     */
    public function push(string $key, $value, string $field = ''): bool
    {
        return $this->_getHandler()->push($key, $value, $field);
    }

    /**
     * 读取缓存并删除
     *
     * @param string $key 缓存变量名
     * @return mixed
     */
    public function pull(string $key)
    {
        return $this->_getHandler()->pull($key);
    }

    /**
     * 如果不存在则写入缓存
     *
     * @param string $key    缓存变量名
     * @param mixed  $value  存储数据
     * @param int    $expire 有效时间 0为永久
     */
    public function remember(string $key, $value, int $expire = 0)
    {
        return $this->_getHandler()->remember($key, $value, $expire);
    }

    /**
     * 判断缓存是否存在
     *
     * @param  string $name 缓存变量名
     */
    public function has($key): bool
    {
        return $this->_getHandler()->has($key);
    }

    /**
     * 获取对象
     */
    private function _getHandler()
    {
        $name = $this->name;
        if ($this->instance[$name]) {
            $this->instance[$name];
        }

        $this->force = true;

        return $this->connect($name, false);
    }
    
    public function __call($method, $args)
    {
        return call_user_func_array([$this->connect($this->name, false), $method], $args);
    }

    public function __destruct()
    {
        //
    }
}